package com.google.com.coma.tester.rmi;

import com.google.code.coma.Coma;
import com.google.code.coma.domain.Computer;
import com.google.code.coma.domain.LifeCycleStep;
import com.google.code.coma.domain.Part;
import com.google.code.coma.rmi.ComputerSelector;
import com.google.code.coma.rmi.RMICallback;
import com.google.code.coma.rmi.RMIManager;
import com.google.code.coma.rmi.storage.StorageService;
import com.google.code.coma.worker.Worker;
import com.google.com.coma.tester.AbstractTesterWorker;
import com.google.com.coma.tester.Tester;
import org.apache.log4j.Logger;

import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.List;

/**
 */
public class RmiTesterWorker extends AbstractTesterWorker implements Worker {
    private static final Logger log = Logger.getLogger(RmiTesterWorker.class);

    private StorageService<Computer> computerStorageService;
    private StorageService<Part> partsStorageService;

    private RMICallback<Computer> exportedCallback = null;

    private RMICallback<Computer> callback;

	private Tester tester;

    public RmiTesterWorker(String factoryId, final Tester tester, LifeCycleStep sourceStep) {
		super(factoryId, sourceStep);

		this.tester = tester;

        computerStorageService = RMIManager.getStorageService(factoryId + "_" + Coma.COMPUTER_CONTAINER);
        partsStorageService = RMIManager.getStorageService(factoryId + "_" + Coma.PARTS_CONTAINER);

        callback = new RMICallback<Computer>() {
            @Override
            public void handle(List<Computer> entries) throws RemoteException {
                Computer computer = entries.get(0);

                tester.testComputer(computer, getWorkerId());

                if (computer.getCurrent().equals(LifeCycleStep.REJECTED)) {
                    for (Part part : getNoneDefectComputerParts(computer)) {
                        partsStorageService.add(part);
                    }
                } else {
                    addComputer(computer, computerStorageService);
                }
            }
        };
    }

    @Override
    public void startWork() {
        try {
            exportedCallback = (RMICallback<Computer>) UnicastRemoteObject.exportObject(callback, 0);
            computerStorageService.registerCallback(new ComputerSelector(sourceStep), callback);
        } catch (RemoteException e) {
            log.error("Error register callback", e);
        }
    }

    private void addComputer(Computer computer, StorageService storageService) throws RemoteException {
        storageService.add(computer);
    }

    @Override
    public void stopWork() {
        if (exportedCallback != null) {
            try {
                UnicastRemoteObject.unexportObject(callback, false);
            } catch (NoSuchObjectException e) {
                log.error("Error unexporting object", e);
            } finally {
                exportedCallback = null;
            }
        }
    }

    @Override
    public boolean isActive() {
        return exportedCallback != null;
    }

}
